// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

using System;
using KnessetCore.Utils;
using log4net;

namespace KnessetCore.Members
{
	/// <summary>
	/// Represents a single knesset member.
	/// </summary>
	public class KnessetMember : IMember, ITimeView
	{
		#region Private vatriables.
		/// <summary>
		/// Holds db id of the member.
		/// </summary>
		private readonly int id;
		/// <summary>
		/// Holds name of the member.
		/// </summary>
		private readonly string name;
		/// <summary>
		/// Log data.
		/// </summary>
		private static readonly ILog logger = LogManager.GetLogger("KnessetCore.Members");
		/// <summary>
		/// Link to image of the knesset member.
		/// </summary>
		private readonly string imgLink;
		/// <summary>
		/// Link to information page on the knesset member.
		/// </summary>
		private readonly string knessetLink;

		#endregion

		#region Constructors
		/// <summary>
		/// Create new member.
		/// </summary>
		/// <param name="id">Db id of the member. Must be positive.</param>
		/// <param name="name">Name of the member can not be null.</param>
		/// <param name="imgLink">ink to image of the knesset member.can not be null</param>
		/// <param name="knessetLink">Link to information page on the knesset member.can not be null</param>
		/// <exception cref="ArgumentOutOfRangeException">Id number must be positive.</exception>
		internal KnessetMember(int id, string name, string imgLink, string knessetLink)
		{
			logger.Debug("~~~~~Entered KnessetMember.KnessetMember");
			if (id <= 0)
			{
				throw new ArgumentOutOfRangeException("Invalid member id: " + id);
			}
			if (name == null) throw new ArgumentNullException("name");
			if (imgLink == null) throw new ArgumentNullException("imgLink");
			if (knessetLink == null) throw new ArgumentNullException("knessetLink");
			this.id = id;
			this.name = name;
			this.knessetLink = knessetLink;
			this.imgLink = imgLink;
			logger.Info(string.Format("Name: {0} ID: {1} Img: {2} Link: {3}", name, id, imgLink, knessetLink));
			logger.Debug("~~~~~Exited KnessetMember.KnessetMember");
		} 
		#endregion

		#region IMember Members

		/// <summary>
		/// Member's db id.
		/// </summary>
		public int Id
		{
			get { return id; }
		}

		/// <summary>
		/// Member's name.
		/// </summary>
		public string Name
		{
			get { return name; }
		}

		/// <summary>
		/// Contains a link to the img to display.
		/// </summary>
		public string ImgLink
		{
			get { return imgLink; }
		}

		/// <summary>
		/// Contains a link to the knesset member's web page on the knesset site.
		/// </summary>
		public string KnessetLink
		{
			get { return knessetLink; }
		}

		#endregion

		#region ITimeView Members

		/// <summary>
		/// Add working hours. The accumulated hours are for today, If you
		/// want to add to a different date use the overloaded method.
		/// </summary>
		/// <param name="span">Working hours to add to the total working hours. Can not be more than 1440 which equals 
		/// to an entire day.</param>
		/// <exception cref="KnessetMembersException">Error while adding working hours.</exception>
		/// <exception cref="ArgumentOutOfRangeException">Time span should be less than 1440.</exception>
		/// <exception cref="MemberDoesNotExistException">Member does not exist.</exception>
		public void AddWorkingHours(TimeSpan span)
		{
			if (span.Minutes > 1440)
			{
				throw new ArgumentOutOfRangeException("Time span should be less than 1440.");
			}
			// Call overloaded method.
			AddWorkingHours(span, DateTime.Today);
			
		}

		/// <summary>
		/// Get total hours accumulated between an interval.
		/// </summary>
		/// <param name="to">End of interval. Value returned includes this day.</param>
		/// <param name="from">Start of interval. Value returned includes this day.</param>
		/// <returns>Total working hours including both 'start' and 'end'</returns>
		/// <exception cref="KnessetMembersException">Error while retrieving working hours.</exception>
		/// <exception cref="ArgumentException">'end' is less than 'start' </exception>
		/// <exception cref="MemberDoesNotExistException">Member does not exist.</exception>
		public TimeSpan GetTotalHours(DateTime to, DateTime from)
		{
			logger.Debug("~~~~~Entered KnessetMember.GetTotalHours");
			logger.Info(string.Format("From: {0} To: {1}", from, to));
			// Make sure that end is more than start.
			if (to.CompareTo(from) < 0)
			{
				throw new ArgumentException("'end' is less than 'start'");
			}
			// Before retrieving hours check that member actually exists.
			int count = (int)Constants.Members.GetCountByName(Name);
			if (count == 0)
			{
				throw new MemberDoesNotExistException(ToString());
			}
			logger.Info(string.Format("Member: {0} exists.", ToString()));
			// Run query and retrieve value.
			Object obj = Constants.Hours.GetTotalHours(id, to, from);
			int minuts = 0;
			// Make sure that we have a result.
			if (obj != null)
			{
				minuts = (int) obj;
			}
			logger.Info(string.Format("Total of minutes are: {0}", minuts));
			logger.Debug("~~~~~Exited KnessetMember.GetTotalHours");
			return new TimeSpan(0, minuts, 0);
		}

		/// <summary>
		/// Add working hours.
		/// </summary>
		/// <param name="span">Working hours to add to the total working hours.</param>
		/// <param name="date">Date to which to add working hours.</param>
		/// <exception cref="KnessetMembersException">Error while adding working hours.</exception>
		/// <exception cref="MemberDoesNotExistException">Member does not exist.</exception>
		public void AddWorkingHours(TimeSpan span, DateTime date)
		{
			logger.Debug("~~~~~Entered KnessetMember.AddWorkingHours");
			logger.Info("Date to add: " + date + ", total time span: " + span + " for member " + ToString());
			// Number of minutes in one day.
			if (span.TotalMinutes > 1440)
			{
				throw new ArgumentOutOfRangeException("Time span should be less than 1440.");
			}
			// Before adding hours check that member actually exists.
			int count = (int) Constants.Members.GetCountByName(Name);
			if (count == 0)
			{
				throw new MemberDoesNotExistException(ToString());
			}
			logger.Info(string.Format("Member: {0} exists.", ToString()));
			// Check if member already has row to the current date, if so then just update otherwise add.
			count = (int)Constants.Hours.Count(Id, date);
			if (count == 1)
			{
				// Add to working hours to db.
				logger.Info("Updating existing hours row.");
				Constants.Hours.AddToAttendingHours((short)span.TotalMinutes, date, Id);
			}
			else
			{
				logger.Info("Adding new hours row.");
				Constants.Hours.Insert(Id, (short)span.TotalMinutes, date);
			}
			logger.Debug("~~~~~Exited KnessetMember.AddWorkingHours");
		}

		#endregion

		#region Object Members
		///<summary>
		///Returns a <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
		///</summary>
		///
		///<returns>
		///A <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
		///</returns>
		///<filterpriority>2</filterpriority>
		public override string ToString()
		{
			return "ID: " + Id + " Name: " + Name;
		} 
		#endregion
	}
}